// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: MIT

package server

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"uos_uwsgi_exporter/internal/config"
)

// TestNewServer 测试服务器创建
func TestNewServer(t *testing.T) {
	cfg := &config.Config{
		Address:     "127.0.0.1",
		Port:        9070,
		MetricsPath: "/metrics",
		RateLimit:   100,
	}

	server := New(cfg)
	if server == nil {
		t.Fatal("Expected server to be created, got nil")
	}

	if server.Addr != "127.0.0.1:9070" {
		t.Errorf("Expected address to be 127.0.0.1:9070, got %s", server.Addr)
	}

	if server.ReadTimeout != 30*time.Second {
		t.Errorf("Expected ReadTimeout to be 30s, got %v", server.ReadTimeout)
	}

	if server.WriteTimeout != 30*time.Second {
		t.Errorf("Expected WriteTimeout to be 30s, got %v", server.WriteTimeout)
	}

	if server.IdleTimeout != 60*time.Second {
		t.Errorf("Expected IdleTimeout to be 60s, got %v", server.IdleTimeout)
	}
}

// TestNewServerWithoutRateLimit 测试无限流的服务器创建
func TestNewServerWithoutRateLimit(t *testing.T) {
	cfg := &config.Config{
		Address:     "127.0.0.1",
		Port:        9070,
		MetricsPath: "/metrics",
		RateLimit:   0, // 无限流
	}

	server := New(cfg)
	if server == nil {
		t.Fatal("Expected server to be created, got nil")
	}

	if server.Addr != "127.0.0.1:9070" {
		t.Errorf("Expected address to be 127.0.0.1:9070, got %s", server.Addr)
	}
}

// TestHandleLandingPage 测试着陆页处理
func TestHandleLandingPage(t *testing.T) {
	req, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatal(err)
	}

	rr := httptest.NewRecorder()
	handler := http.HandlerFunc(handleLandingPage)

	handler.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusOK {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
	}

	contentType := rr.Header().Get("Content-Type")
	if contentType != "text/html; charset=utf-8" {
		t.Errorf("handler returned wrong content type: got %v want %v", contentType, "text/html; charset=utf-8")
	}

	body := rr.Body.String()
	if !strings.Contains(body, "uWSGI Exporter") {
		t.Error("handler returned unexpected body: should contain 'uWSGI Exporter'")
	}

	if !strings.Contains(body, "/metrics") {
		t.Error("handler returned unexpected body: should contain '/metrics'")
	}

	if !strings.Contains(body, "/healthz") {
		t.Error("handler returned unexpected body: should contain '/healthz'")
	}
}

// TestHandleLandingPageNotFound 测试着陆页404处理
func TestHandleLandingPageNotFound(t *testing.T) {
	req, err := http.NewRequest("GET", "/nonexistent", nil)
	if err != nil {
		t.Fatal(err)
	}

	rr := httptest.NewRecorder()
	handler := http.HandlerFunc(handleLandingPage)

	handler.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusNotFound {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound)
	}
}

// TestHandleHealthCheck 测试健康检查处理
func TestHandleHealthCheck(t *testing.T) {
	req, err := http.NewRequest("GET", "/healthz", nil)
	if err != nil {
		t.Fatal(err)
	}

	rr := httptest.NewRecorder()
	handler := http.HandlerFunc(handleHealthCheck)

	handler.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusOK {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
	}

	contentType := rr.Header().Get("Content-Type")
	if contentType != "application/json" {
		t.Errorf("handler returned wrong content type: got %v want %v", contentType, "application/json")
	}

	body := rr.Body.String()
	if !strings.Contains(body, `"status":"ok"`) {
		t.Error("handler returned unexpected body: should contain 'status:ok'")
	}

	if !strings.Contains(body, `"timestamp"`) {
		t.Error("handler returned unexpected body: should contain 'timestamp'")
	}

	// 验证JSON格式
	var response map[string]interface{}
	if err := json.Unmarshal([]byte(body), &response); err != nil {
		t.Errorf("handler returned invalid JSON: %v", err)
	}

	if status, ok := response["status"].(string); !ok || status != "ok" {
		t.Errorf("handler returned wrong status: got %v want 'ok'", status)
	}

	if _, ok := response["timestamp"].(string); !ok {
		t.Error("handler returned missing or invalid timestamp")
	}
}

// TestServerEndpoints 测试服务器端点的集成测试
func TestServerEndpoints(t *testing.T) {
	cfg := &config.Config{
		Address:     "127.0.0.1",
		Port:        0, // 使用随机端口
		MetricsPath: "/metrics",
		RateLimit:   0,
		Sockets:     []string{"/tmp/test.sock"},
	}

	server := New(cfg)
	if server == nil {
		t.Fatal("Expected server to be created, got nil")
	}

	// 启动测试服务器
	listener, err := net.Listen("tcp", server.Addr)
	if err != nil {
		t.Fatalf("Failed to create listener: %v", err)
	}
	defer listener.Close()

	// 获取实际监听的地址
	addr := listener.Addr().String()

	go func() {
		if err := server.Serve(listener); err != nil && err != http.ErrServerClosed {
			t.Errorf("server error: %v", err)
		}
	}()

	// 等待服务器启动
	time.Sleep(100 * time.Millisecond)

	// 测试健康检查端点
	resp, err := http.Get(fmt.Sprintf("http://%s/healthz", addr))
	if err != nil {
		t.Fatalf("Failed to get health check: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		t.Errorf("Expected status 200, got %d", resp.StatusCode)
	}

	// 测试指标端点
	resp, err = http.Get(fmt.Sprintf("http://%s%s", addr, cfg.MetricsPath))
	if err != nil {
		t.Fatalf("Failed to get metrics: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		t.Errorf("Expected status 200, got %d", resp.StatusCode)
	}

	// 关闭服务器
	server.Close()
}

// BenchmarkHandleHealthCheck 健康检查性能测试
func BenchmarkHandleHealthCheck(b *testing.B) {
	req, err := http.NewRequest("GET", "/healthz", nil)
	if err != nil {
		b.Fatal(err)
	}

	rr := httptest.NewRecorder()
	handler := http.HandlerFunc(handleHealthCheck)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		handler.ServeHTTP(rr, req)
	}
}

// BenchmarkHandleLandingPage 着陆页性能测试
func BenchmarkHandleLandingPage(b *testing.B) {
	req, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		b.Fatal(err)
	}

	rr := httptest.NewRecorder()
	handler := http.HandlerFunc(handleLandingPage)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		handler.ServeHTTP(rr, req)
	}
}
